package ro.upt.ac.cstaicu.execution.junit;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;

import org.junit.runner.JUnitCore;
import org.junit.runner.Result;

import ro.upt.ac.cstaicu.execution.CustomClassLoader;
import ro.upt.ac.cstaicu.execution.Executor;
import ro.upt.ac.cstaicu.execution.TestResult;
import ro.upt.ac.cstaicu.instrumentation.Instrumentor;
import ro.upt.ac.cstaicu.instrumentation.logging.GlobalLogger;
import ro.upt.ac.cstaicu.instrumentation.logging.PredicateCounterLogger;

/**
 * It implements the {@link Executor} interface using the junit framework. It's
 * main method executes a test cases an stores it's runing time.
 * 
 * @author Cristian-Alexandru STAICU
 */
public class JunitFacade implements Executor {
	
	private ArrayList<TestResult> results = new ArrayList<TestResult>();
	private GlobalLogger logger;
	private Instrumentor instrumentationModule;
	private Collection<String> ignoredTests;
	private CustomClassLoader cl;

	public JunitFacade(Instrumentor instrumentationModule,
			GlobalLogger logger, Collection<String> ignoredTests) {
		this.ignoredTests = ignoredTests;
		this.instrumentationModule = instrumentationModule;
		this.logger = logger;
	}

	/**
	 * It runs the testcase using a {@link JUnitCore} class and a
	 * {@link JunitTestResultListener}. A {@link CustomClassLoader} is used to
	 * load the desired class. After the test has finished it's running time is
	 * logged using a {@link GlobalLogger}
	 * 
	 * @param projectClassPath
	 *            - path to the analyzed project
	 * @param className
	 *            - the name of the class to be executed
	 */
	@Override
	public void executeTestClass(File[] classPathEntries, String projectClassPath, String className) {
		JUnitCore junit = new JUnitCore();
		
		cl = new CustomClassLoader(classPathEntries, projectClassPath, JUnitCore.class.getClassLoader(), instrumentationModule, logger, ignoredTests);

		try {
			JunitTestResultListener listener = new JunitTestResultListener();

			junit.addListener(listener);

			Class<?> testClass = cl.loadClass(className);
			
			Result res = junit.run(testClass);

			// TODO use polymorphism/composition
			PredicateCounterLogger.getInstance().setRunningTime(
					res.getRunTime());

//			for (TestResult result : listener.getResults()) {
//				results.add(result);
//				System.out.println(result);
//			}
			results.addAll(listener.getResults());
			junit.removeListener(listener);
//			System.out.println("BEFORE = " + Thread.currentThread().getThreadGroup().activeCount());
			stopAllThreads();
//			System.out.println("AFTER = " + Thread.currentThread().getThreadGroup().activeCount());
		} catch (ClassNotFoundException e) {
			// TODO catch exception
			System.out.println(e);
		}
	}
	
	private void stopAllThreads() {
		Thread[] threads = new Thread[Thread.currentThread().getThreadGroup().activeCount()];
		Thread.currentThread().getThreadGroup().enumerate(threads);
		Thread currentThread = Thread.currentThread();
		for (Thread t : threads) {
			if (!t.equals(currentThread))	
				t.stop();
		}
		
	}

	/**
	 * Returns a list with the results of all executed tests.
	 */
	public ArrayList<TestResult> getTestResults() {
		return results;
	}

	@Override
	public void clean() {
		cl.clearHistory();		
	}

}
